﻿using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data.SqlClient;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Threading;
using Tools;
using WPF数据采集系统.BLL;
using WPF数据采集系统.MesClass;
using WPF数据采集系统.Model;
using WPF数据采集系统.ViewModel;

namespace WPF数据采集系统.Base
{
    public class PlcStateMonitor
    {
        public static System.Threading.Timer timer = new System.Threading.Timer(PlcStateMonitor.timer_Elapsed, null, 0, 2000);
        public static System.Threading.Timer MesTimer = new System.Threading.Timer(PlcStateMonitor.MesTimer_Elapsed, null, 0, 5000);
        public static string PlcContent = "Connecting";
        public static string MesContent = "Disconnect";
        public static ResultGetProcessRoute rgpr;//托盘路由返回信息
        public static GetProcessRoute gpr;//托盘路由信息
        public static string PlcStatus = string.Empty;
        /// <summary>
        /// 固定监控值开始执行
        /// </summary>
        /// <param name="PlcState"></param>
        public void MainRun(bool PlcState)
        {
            PlcContent = "Connecting";
            PlcViewModel pvm = new PlcViewModel();
            ObservableCollection<PlcModel> PlcList = pvm.plcInfoList;
            ObservableCollection<PlcMonitorInfo> PlcMonitorInfoList = pvm.plcMonitorInfoList;
            PlcMonitorInfoList.OrderBy(t => (t.sort));//监控值排序
            Action<object> action = (object obj) =>
            {
                int i = (int)obj;
                PlcTool plc = new PlcTool();
                plc.remotoIP = PlcList[i].PlcIp;
                plc.remotoPort = PlcList[i].PlcPort;
                plc.plcId = PlcList[i].PlcId;

                var CioIntList = PlcMonitorInfoList.Where(pmi => (pmi.data_type == "INT" && pmi.type == "CIO")).ToList();//CIO-INT类型筛选
                var DMIntList = PlcMonitorInfoList.Where(pmi => (pmi.data_type == "INT" && pmi.type == "DM")).ToList();//DM-INT类型筛选     
                Task task1 = null;

                if (CioIntList.Count() > 0 && DMIntList.Count() > 0)
                {
                    task1 = Task.Factory.StartNew(() => {
                        ReadPlcInt(CioIntList, plc);
                    });
                    task1.Wait();
                    Task task2 = Task.Factory.StartNew(() => {
                        ReadPlcInt(DMIntList, plc);
                    });
                }
            };
            try
            {
                var tasks = new Task[PlcList.Count];
                for (int i = 0; i < PlcList.Count; i++)
                {
                    if(PlcList[i].Usability)
                        tasks[i] = Task.Factory.StartNew(action, i);
                }
            }
            catch (Exception ex)
            {
                ListBoxHelper.listBoxAdd(MainWindow.mvm.logListBox, ex.Message, true);
            }
        }
        public void ReadPlcInt(List<PlcMonitorInfo> MonitorList,PlcTool plc)
        {
            int start_address =MonitorList.Min(t => (t.address));
            int read_len = MonitorList.Sum(tt => (tt.length));
            string type = MonitorList[0].type;
            int i = 1;//异常次数控制
            while (MainWindow.mvm.PlcState)
            {
                DateTime dt1 = DateTime.Now;
                DataResult<byte[]> plcReadResult;
                plc.ReadInt(type, start_address, read_len, out plcReadResult);
                Task task1 = Task.Factory.StartNew(() => {
                    MonitorMain(plc);//监控命令
                });
                task1.Wait();
                if (plcReadResult.State)
                {
                    int r = 0;
                    PlcContent = "Normal";
                    foreach (PlcMonitorInfo pmi in MonitorList)
                    {
                        LogModel lm = new LogModel();
                        lm.DeviceName = pmi.name;
                        lm.LogInfo = type + pmi.address;
                        lm.RowNumber = plc.plcId;
                        PlcStateType pst = (PlcStateType)((plcReadResult.Data[14 + r] * 256) + plcReadResult.Data[14 + r + 1]);
                        lm.Message = pst.ToString();
                        lm.LogType = LogType.Fault;
                        if (pmi.enable && pmi.display)
                        {
                            switch(pmi.address)
                            {
                                case 1000:
                                    if(pmi.type == "CIO" && lm.Message=="1")
                                    {
                                        int[] b = new int[2];
                                        b[0] = 2;
                                        //plc.write(type,1000,2, b);
                                        lm.LogType = LogType.Fault;
                                    }
                                    else if(pmi.type == "DM")
                                    {
                                        PlcStatus = pst.ToString();
                                    }
                                    else
                                    {
                                        lm.LogType = LogType.Warn;
                                    }
                                    break;
                                case 1001:
                                    if (pmi.type == "CIO" && lm.Message == "1")
                                    {
                                        lm.Message = "暂停";
                                        lm.LogType = LogType.Warn;
                                    }
                                    break;
                                case 1002:
                                    if (pmi.type == "CIO" && lm.Message == "1")
                                    {
                                        lm.Message = "屏蔽上位机";
                                        lm.LogType = LogType.Warn;
                                    }
                                    break;
                                case 1003:
                                    if (pmi.type == "CIO" && lm.Message == "1")
                                    {
                                        lm.Message = "MES断开,请检查";
                                        lm.LogType = LogType.Warn;
                                    }
                                    break;
                                case 1004:
                                    if (pmi.type == "CIO" && lm.Message == "0")
                                    {
                                        lm.Message = "状态异常";
                                        lm.LogType = LogType.Warn;
                                    }
                                    break;
                                default:
                                    if (((pmi.address == 1008 || pmi.address == 1011 || pmi.address == 1014 || pmi.address == 1017 || pmi.address == 1020 || pmi.address == 1023 || pmi.address == 1026) && pmi.type == "DM"))
                                    {
                                        lm.Message = (plcReadResult.Data[14 + r] * 256) + plcReadResult.Data[14 + r + 1].ToString() + ":" +
                                            (plcReadResult.Data[14 + r + 2] * 256) + plcReadResult.Data[14 + r + 3].ToString() + ":" +
                                            (plcReadResult.Data[14 + r + 4] * 256) + plcReadResult.Data[14 + r + 5].ToString();
                                        r += 4;
                                    }
                                    break;
                            }
                            LogListSet(lm);
                        }
                        r += 2;
                    }
                    DateTime dt2 = DateTime.Now;
                    int timespan = dt2.Subtract(dt1).Milliseconds;
                    if(1000-timespan>0)
                    {
                        Thread.Sleep(1000 - timespan);
                    }
                    i = 1;
                }
                else
                {
                    //ListBoxHelper.listBoxAdd(MainWindow.mvm.logListBox, "网络异常,PLC"+plc.plcId+"连接失败,正在尝试第" + i + "次重连...", false);
                    foreach (PlcMonitorInfo pmi in MonitorList)
                    {
                        LogModel lm = new LogModel();
                        lm.DeviceName = pmi.name;
                        lm.LogInfo = type + pmi.address;
                        lm.RowNumber = plc.plcId;
                        lm.Message = "异常" + i + "次";
                        lm.LogType = LogType.Warn;
                        if(pmi.enable&&pmi.display)
                        {
                            LogListSet(lm);
                        }
                    }
                    i++;
                    if (i == 4)
                    {
                        MainWindow.mvm.PlcState = false;
                        PlcContent = "ERROR";
                        ListBoxHelper.listBoxAdd(MainWindow.mvm.logListBox, "由于多次尝试连接PLC" + plc.plcId + "失败,程序已停止自动连接,请确保网络和PLC配置正确后重试!", true);
                    }
                    DateTime dt2 = DateTime.Now;
                    int timespan = dt2.Subtract(dt1).Milliseconds;
                    if (1000 - timespan > 0)
                    {
                        Thread.Sleep(1000 - timespan);
                    }
                }
            }
            PlcContent = "ERROR";
            foreach (PlcMonitorInfo pmi in MonitorList)
            {
                LogModel lm = new LogModel();
                lm.DeviceName = pmi.name;
                lm.LogInfo = type + pmi.address;
                lm.RowNumber = plc.plcId;
                lm.Message = "停止监测";
                lm.LogType = LogType.Warn;
                if (pmi.enable && pmi.display)
                {
                    LogListSet(lm);
                }
            }
        }

        public void MonitorMain(PlcTool plc)
        {
            try
            {
                DataResult<byte[]> plcReadResult;
                plc.ReadInt("CIO",1200,4,out plcReadResult);//1200,1201
                if (plcReadResult.State)
                {
                    int[] Monitor = PlcTool.GetFinsDataInt(plcReadResult.Data, 2);
                    if (Monitor[0]==1)
                    {
                        int codelength = Monitor[1];
                        DataResult<byte[]> CodeResult;
                        plc.ReadInt("CIO", 1202, codelength, out CodeResult);//读取条码
                        string Code;
                        if(CodeResult.State)
                        {
                            int len = CodeResult.Data.Length;
                            byte[] b = new byte[len - 14];
                            for (int r = 0; r < len; r += 2)
                            {
                                if (r + 1 == len)
                                {
                                    b[r] = CodeResult.Data[14 + r];
                                }
                                else
                                {
                                    b[r] = CodeResult.Data[14 + r + 1];
                                    b[r + 1] = CodeResult.Data[14 + r];
                                }
                            }
                            Code = Encoding.ASCII.GetString(b);
                            gpr = new GetProcessRoute();
                            gpr.param = new GetProcessRouteParam();
                            gpr.action = "set_device_status";
                            gpr.param.tray = Code;
                            string result = string.Empty;
                            string sendData = JsonConvert.SerializeObject(gpr);
                            int re = HttpHelper.HttpPost("http://8.sctmes.com:38000", sendData, out result);
                            if (re == 0)
                            {
                                rgpr = new ResultGetProcessRoute();
                                rgpr = JsonConvert.DeserializeObject<ResultGetProcessRoute>(result);
                                if(rgpr.errcode==0)
                                {
                                    string sql = "INSERT INTO [dbo].[ProcessRoute]([日期],[接口名称],[托盘号],[返回码],[生产批次],[子批次],[流水号],[上一工序编码],[下一工序编码],[上一工作站],[下一工作站],[投入电池数量],[错误信息],[返回结果],[操作人]) " +
                                        "Values(@datetime,@name,@tray,@errcode,@batch,@unit_batch,@lot,@lastProcess,@nextProcess,@lastWorkStation,@nextWorkStation,@inputBatteryCount,@errMsg,@result,@operter)";
                                    SqlParameter[] param1 = new SqlParameter[]
                                    {
                                        new SqlParameter("@datetime",DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")),
                                        new SqlParameter("@name",gpr.action),
                                        new SqlParameter("@tray",gpr.param.tray),
                                        new SqlParameter("@errcode",rgpr.errcode),
                                        new SqlParameter("@batch",rgpr.rtval.batch),
                                        new SqlParameter("@unit_batch",rgpr.rtval.unit_batch),
                                        new SqlParameter("@lot",rgpr.rtval.lot),
                                        new SqlParameter("@lastProcess",rgpr.rtval.lastProcess),
                                        new SqlParameter("@nextProcess",rgpr.rtval.nextProcess),
                                        new SqlParameter("@lastWorkStation",rgpr.rtval.lastWorkstation),
                                        new SqlParameter("@nextWorkStation",rgpr.rtval.nextWorkstation),
                                        new SqlParameter("@inputBatteryCount",rgpr.rtval.inputBatteryCount),
                                        new SqlParameter("@errMsg",rgpr.errmsg),
                                        new SqlParameter("@result",rgpr.rtval),
                                        new SqlParameter("@operter",MainWindow.LoginUser)
                                    };
                                    MainWindow.mvm.RotateListInIt(rgpr.rtval.inputBatteryCount);
                                    SqlHelper.Update(sql, param1);
                                }
                            }
                            GetTrayInfo gri = new GetTrayInfo();
                            gri.param = new GetTrayInfoParam();
                            gri.action = "get_tray_info";
                            gri.param.tray = Code;
                            result = string.Empty;
                            string GetTrayInfoData = JsonConvert.SerializeObject(gpr);
                            int gtir = HttpHelper.HttpPost("http://8.sctmes.com:38000", sendData, out result);
                            if(gtir==0)
                            {
                                ResultGetTrayInfo rsds = new ResultGetTrayInfo();
                                rsds = JsonConvert.DeserializeObject<ResultGetTrayInfo>(result);
                                if (rsds.errcode == 0)
                                {
                                    string sql = "INSERT INTO [dbo].[TrayInfo]([日期],[接口名称],[托盘号],[返回码],[返回结果],[生产批次],[子批次],[电池型号],[流水号],[是否整盘NG],[下一工序编码],[整盘NG类别],[整盘NG设备],[投入电池数量],[错误信息]]) " +
                                        "Values(@datetime,@name,@tray,@errcode,@result,@batch,@unit_batch,@model,@lot,@isAllNg,@allNgClass,@allNgDevice,@errMsg)";
                                    SqlParameter[] param1 = new SqlParameter[]
                                    {
                                        new SqlParameter("@datetime",DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")),
                                        new SqlParameter("@name",gpr.action),
                                        new SqlParameter("@tray",gpr.param.tray),
                                        new SqlParameter("@errcode",rsds.errcode),
                                        new SqlParameter("@result",rsds.rtval),
                                        new SqlParameter("@batch",rsds.rtval.batch),
                                        new SqlParameter("@unit_batch",rsds.rtval.unit_batch),
                                        new SqlParameter("@model",rsds.rtval.model),
                                        new SqlParameter("@lot",rsds.rtval.lot),
                                        new SqlParameter("@isAllNg",rsds.rtval.tray_ng),
                                        new SqlParameter("@allNgClass",rsds.rtval.tray_ng_class),
                                        new SqlParameter("@allNgDevice",rsds.rtval.tray_ng_device),
                                        new SqlParameter("@errMsg",rsds.errmsg),
                                    };
                                    List<string> l1 = rsds.rtval.battery_ids;
                                    List<string> l2 = rsds.rtval.ng_class;
                                    List<string> l3 = rsds.rtval.ng_classname;
                                    List<int> l4 = rsds.rtval.active;
                                    for (int f=0;f<l1.Count;f++)
                                    {
                                        string insertsql = "INSERT INTO [dbo].[TrayInfo_sub]([托盘号],[电池编码],[激活状态],[电池类别],[电池等级]) " +
                                            "Values(@tray,@bacthcode,@active,@class,@grade)";
                                        SqlParameter[] param2 = new SqlParameter[]
                                        {
                                            new SqlParameter("@tray",DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")),
                                            new SqlParameter("@bacthcode",l1[f]),
                                            new SqlParameter("@active",l4[f]),
                                            new SqlParameter("@class",l2[f]),
                                            new SqlParameter("@grade",l3[f])
                                        };
                                        SqlHelper.Update(insertsql, param2);
                                    }
                                    SqlHelper.Update(sql, param1);
                                }
                            }
                        }
                    }
                }
                DataResult<byte[]> DepartureReadResult;
                plc.ReadInt("CIO", 1203, 8, out DepartureReadResult);
                if (DepartureReadResult.State)
                {
                    ThreadPool.QueueUserWorkItem(delegate
                    {
                        SynchronizationContext.SetSynchronizationContext(new
                            DispatcherSynchronizationContext(System.Windows.Application.Current.Dispatcher));
                        SynchronizationContext.Current.Post(pl =>
                        {
                            MainWindow.mvm.RotateListInIt(50);
                        }, null);
                    });
                    int[] Monitor = PlcTool.GetFinsDataInt(DepartureReadResult.Data, 4);//1203,1204,1205,1206
                    {

                        if(Monitor[1]!=50 && Monitor[1] != 52)//1204
                        {
                            ListBoxHelper.RotateListSet(Monitor[1], Monitor);
                            int[] sd1 = new int[1];
                            sd1[0] = 50;
                            plc.write("CIO", 1204, 1, sd1);
                        }
                        if(Monitor[2] != 50 && Monitor[2] != 52)//1205
                        {
                            ListBoxHelper.RotateListSet(Monitor[2], Monitor);
                            int[] sd1 = new int[1];
                            sd1[0] = 50;
                            plc.write("CIO", 1205, 1, sd1);
                        }
                        if (Monitor[3] != 50 && Monitor[3] != 52)//1206
                        {
                            ListBoxHelper.RotateListSet(Monitor[3], Monitor);
                            int[] sd1 = new int[1];
                            sd1[0] = 50;
                            plc.write("CIO", 1205, 1, sd1);
                        }
                        if(Monitor[0]==1)//1203出站
                        {
                            SetProcessResult spr = new SetProcessResult();
                            spr.param = new SetProcessResultParam();
                            spr.action = "set_process_result";
                            spr.process_code = rgpr.rtval.nextProcess;
                            spr.param.tray = gpr.param.tray;
                            List<string> list = new List<string>(MainWindow.mvm.RotateList.Count);
                            for(int i=0;i< MainWindow.mvm.RotateList.Count;i++)
                            {
                                list[i] = MainWindow.mvm.RotateList[i].RotateTime;
                            }
                            spr.param.Time = list;
                            string result = string.Empty;
                            string SetProcessResultData = JsonConvert.SerializeObject(spr);
                            int gtir = HttpHelper.HttpPost("http://8.sctmes.com:38000", SetProcessResultData, out result);
                            if(gtir==0)
                            {
                                ResultGetTrayInfo grip = JsonConvert.DeserializeObject<ResultGetTrayInfo>(result);
                                if(grip.errcode==0)
                                {
                                    int[] sd1 = new int[1];
                                    sd1[0] = 2;
                                    plc.write("CIO", 1203, 1, sd1);
                                }
                                else//上传结果失败
                                {
                                    int[] sd1 = new int[1];
                                    sd1[0] = 6;
                                    plc.write("CIO", 1203, 1, sd1);
                                }

                            }
                        }                    
                    }
                }
            }
            catch (Exception ex)
            {
                ListBoxHelper.listBoxAdd(MainWindow.mvm.logListBox, ex.Message);
            }
        }
        public string ReadPlcStr(int read_len,int start, PlcTool plc)
        {
            DataResult<byte[]> plcReadResult;
            plc.ReadInt("DM", start, read_len, out plcReadResult);
            if (plcReadResult.State)
            {
                PlcContent = "Normal " + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
                string value = string.Empty;
                int len = plcReadResult.Data.Length;
                byte[] b = new byte[len-14];
                for(int r = 0;r < len;r += 2)
                {
                    if(r+1 == len)
                    {
                        b[r] = plcReadResult.Data[14 + r];
                    }
                    else
                    {
                        b[r] = plcReadResult.Data[14 + r + 1];
                        b[r + 1] = plcReadResult.Data[14 + r];
                    }
                }
                return Encoding.ASCII.GetString(b);               
            }
            else
            {
                return null;
            }
        }
        public void LogListSet(LogModel lm)
        {
            System.Windows.Application.Current.Dispatcher.BeginInvoke(new Action(() =>
            {
                int i = MainWindow.mvm.MonitorList.Count;
                //if (MainWindow.mvm.MonitorList.Count == 20)
                //{
                //    MainWindow.mvm.MonitorList.RemoveAt(19);
                //}
                var item = MainWindow.mvm.MonitorList.Where(t => (t.RowNumber == lm.RowNumber && t.DeviceName == lm.DeviceName));                
                if (item.Count() > 0)
                {
                    i = MainWindow.mvm.MonitorList.IndexOf(item.First());
                    MainWindow.mvm.MonitorList.RemoveAt(i);
                }
                MainWindow.mvm.MonitorList.Insert(i,lm);
            }));

        }
        public static void timer_Elapsed(object sender)
        {
            
            if (PlcContent.Contains("Connecting"))
            {
                MainWindow.mvm.PlcBackGround = "light_red";
                MainWindow.mvm.PlcContent = PlcContent;
                Thread.Sleep(500);
                MainWindow.mvm.PlcContent = PlcContent + ".";
                Thread.Sleep(500);
                MainWindow.mvm.PlcContent = PlcContent + "..";
                Thread.Sleep(500);
                MainWindow.mvm.PlcContent = PlcContent + "...";
                Thread.Sleep(500);
            }
            else if(PlcContent.Contains("Normal"))
            {
                MainWindow.mvm.PlcBackGround = "green";
                MainWindow.mvm.PlcContent = "Normal " + DateTime.Now.ToString("HH:mm:ss"); 
                Thread.Sleep(500);
                MainWindow.mvm.PlcBackGround = "light_green";
                Thread.Sleep(500);
                MainWindow.mvm.PlcBackGround = "green";
                MainWindow.mvm.PlcContent = "Normal " + DateTime.Now.ToString("HH:mm:ss");
                Thread.Sleep(500);
                MainWindow.mvm.PlcBackGround = "light_green";
                Thread.Sleep(500);
            }
            else
            {
                MainWindow.mvm.PlcBackGround = "red";
                Thread.Sleep(500);
                MainWindow.mvm.PlcContent = "Disconnect " + DateTime.Now.ToString("HH:mm:ss");
                MainWindow.mvm.PlcBackGround = "light_red";
                Thread.Sleep(500);
                MainWindow.mvm.PlcBackGround = "red";
                Thread.Sleep(500);
                MainWindow.mvm.PlcContent = "Disconnect " + DateTime.Now.ToString("HH:mm:ss");
                MainWindow.mvm.PlcBackGround = "light_red";
                Thread.Sleep(500);
            }
        }
        public static void MesTimer_Elapsed(object sender)
        {
            SetDeviceStatus sds = new SetDeviceStatus();
            sds.param = new SetDeviceStatusParam();
            sds.action = "set_device_status";
            sds.param.device_code = "ROTATE";

            //if(!string.IsNullOrWhiteSpace(PlcStatus))
            //{
            //    PlcStatus = string.Empty;
            //} 
            sds.param.status = PlcStatus;
            sds.param.errcode = "1020";
            sds.param.msg = "";
            string result = string.Empty;
            string sendData = JsonConvert.SerializeObject(sds);
            int re = HttpHelper.HttpPost("http://8.sctmes.com:38000", sendData, out result);
            if (re == 0)
            {
                ResultSetDeviceStatus rsds = JsonConvert.DeserializeObject<ResultSetDeviceStatus>(result);
                if (rsds.errcode == 0)
                {
                    MesContent = "Normal";
                }
                else
                {
                    MesContent = rsds.errmsg;
                    ListBoxHelper.listBoxAdd(MainWindow.mvm.logListBox, "Mes发送设备状态失败:" + MesContent);
                }
            }
            else
            {
                MesContent = "Error";
            }
            if (MesContent.Contains("Normal"))
            {
                MainWindow.mvm.MesBackGround = "green";
                MainWindow.mvm.MesContent = "Normal ";
                //Thread.Sleep(1000);
                //MainWindow.mvm.MesBackGround = "light_green";
                //Thread.Sleep(1000);
                //MainWindow.mvm.MesBackGround = "green";
                //MainWindow.mvm.MesContent = "Normal " + DateTime.Now.ToString("HH:mm:ss");
                //Thread.Sleep(1000);
                //MainWindow.mvm.MesBackGround = "light_green";
                //Thread.Sleep(1000);
            }
            else
            {
                MainWindow.mvm.MesBackGround = "red";
                MainWindow.mvm.MesContent = MesContent;
                Thread.Sleep(1000);
                //MainWindow.mvm.MesBackGround = "light_red";
                //Thread.Sleep(1000);
                //MainWindow.mvm.MesBackGround = "red";
                //Thread.Sleep(1000);
                //MainWindow.mvm.MesContent = MesContent + DateTime.Now.ToString("HH:mm:ss");
                //MainWindow.mvm.MesBackGround = "light_red";
                //Thread.Sleep(1000);
            }
        }
    }
}
